home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 45
/
Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso
/
Aminet
/
gfx
/
x11
/
x3270_3_2_16.lha
/
amiga_src
/
popups.c
< prev
next >
Wrap
C/C++ Source or Header
|
2009-02-26
|
15KB
|
653 lines
/*
* Copyright 1993, 1994, 1995, 1999, 2000 by Paul Mattes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*/
/*
* popups.c
* This module handles pop-up dialogs: errors, host names,
* font names, information.
*/
#include "globals.h"
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Text.h>
#include <stdarg.h>
#include "objects.h"
#include "appres.h"
#include "actionsc.h"
#include "macrosc.h"
#include "popupsc.h"
#include "screenc.h"
#include "utilc.h"
#include "xioc.h"
static char vmsgbuf[4096];
static enum form_type forms[] = { FORM_NO_WHITE, FORM_NO_CC, FORM_AS_IS };
/*
* General popup support
*/
/* Find the parent of a window */
static Window
parent_of(Window w)
{
Window root, parent, *wchildren;
unsigned int nchildren;
XQueryTree(display, w, &root, &parent, &wchildren, &nchildren);
XFree((char *)wchildren);
return parent;
}
/*
* Find the base window (the one with the wmgr decorations) and the virtual
* root, so we can pop up a window relative to them.
*/
void
toplevel_geometry(Position *x, Position *y, Dimension *width,
Dimension *height)
{
Window tlw = XtWindow(toplevel);
Window win;
Window parent;
int nw;
struct {
Window w;
XWindowAttributes wa;
} ancestor[10];
XWindowAttributes wa, *base_wa, *root_wa;
/*
* Trace the family tree of toplevel.
*/
for (win = tlw, nw = 0; ; win = parent) {
parent = parent_of(win);
ancestor[nw].w = parent;
XGetWindowAttributes(display, parent, &ancestor[nw].wa);
++nw;
if (parent == root_window)
break;
}
/*
* Figure out if they're running a virtual desktop, by seeing if
* the 1st child of root is bigger than it is. If so, pretend that
* the virtual desktop is the root.
*/
if (nw > 1 &&
(ancestor[nw-2].wa.width > ancestor[nw-1].wa.width ||
ancestor[nw-2].wa.height > ancestor[nw-1].wa.height))
--nw;
root_wa = &ancestor[nw-1].wa;
/*
* Now identify the base window as the window below the root
* window.
*/
if (nw >= 2) {
base_wa = &ancestor[nw-2].wa;
} else {
XGetWindowAttributes(display, tlw, &wa);
base_wa = &wa;
}
*x = base_wa->x + root_wa->x;
*y = base_wa->y + root_wa->y;
*width = base_wa->width + 2*base_wa->border_width;
*height = base_wa->height + 2*base_wa->border_width;
}
/* Pop up a popup shell */
void
popup_popup(Widget shell, XtGrabKind grab)
{
XtPopup(shell, grab);
XSetWMProtocols(display, XtWindow(shell), &a_delete_me, 1);
}
static enum placement CenterD = Center;
enum placement *CenterP = &CenterD;
static enum placement BottomD = Bottom;
enum placement *BottomP = &BottomD;
static enum placement LeftD = Left;
enum placement *LeftP = &LeftD;
static enum placement RightD = Right;
enum placement *RightP = &RightD;
/* Place a popped-up shell */
void
place_popup(Widget w, XtPointer client_data, XtPointer call_data unused)
{
Dimension width, height;
Position x = 0, y = 0;
Dimension win_width, win_height;
Dimension popup_width, popup_height;
enum placement p = *(enum placement *)client_data;
/* Get and fix the popup's dimensions */
XtRealizeWidget(w);
XtVaGetValues(w,
XtNwidth, &width,
XtNheight, &height,
NULL);
XtVaSetValues(w,
XtNheight, height,
XtNwidth, width,
XtNbaseHeight, height,
XtNbaseWidth, width,
XtNminHeight, height,
XtNminWidth, width,
XtNmaxHeight, height,
XtNmaxWidth, width,
NULL);
/*
* Find the geometry of the parent of the toplevel window in order to
* place the popup window. This is done with an Xlib call (asking the
* server explicitly) rather than the Xt call. Why? At startup,
* Xt may not yet know the parent window has been moved by the window
* manager.
*/
toplevel_geometry(&x, &y, &win_width, &win_height);
switch (p) {
case Center:
XtVaGetValues(w,
XtNwidth, &popup_width,
XtNheight, &popup_height,
NULL);
XtVaSetValues(w,
XtNx, x + (win_width-popup_width) / (unsigned) 2,
XtNy, y + (win_height-popup_height) / (unsigned) 2,
NULL);
break;
case Bottom:
XtVaSetValues(w,
XtNx, x,
XtNy, y + win_height + 2,
NULL);
break;
case Left:
XtVaGetValues(w,
XtNwidth, &popup_width,
NULL);
XtVaSetValues(w,
XtNx, x - popup_width - (win_width - main_width) - 2,
XtNy, y,
NULL);
break;
case Right:
XtVaSetValues(w,
XtNx, x + win_width + 2,
XtNy, y,
NULL);
break;
}
}
/* Action called when "Return" is pressed in data entry popup */
void
PA_confirm_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
Widget w2;
/* Find the Confirm or Okay button */
w2 = XtNameToWidget(XtParent(w), ObjConfirmButton);
if (w2 == NULL)
w2 = XtNameToWidget(XtParent(w), ObjConfirmButton);
if (w2 == NULL)
w2 = XtNameToWidget(w, ObjConfirmButton);
if (w2 == NULL) {
xs_warning("confirm: cannot find %s", ObjConfirmButton);
return;
}
/* Call its "notify" event */
XtCallActionProc(w2, "set", event, params, *num_params);
XtCallActionProc(w2, "notify", event, params, *num_params);
XtCallActionProc(w2, "unset", event, params, *num_params);
}
/* Callback for "Cancel" button in data entry popup */
static void
cancel_button_callback(Widget w unused, XtPointer client_data,
XtPointer call_data unused)
{
XtPopdown((Widget) client_data);
}
/*
* Callback for text source changes. Ensures that the dialog text does not
* contain white space -- especially newlines.
*/
static void
popup_dialog_callback(Widget w, XtPointer client_data,
XtPointer call_data unused)
{
static Boolean called_back = False;
XawTextBlock b, nullb; /* firstPos, length, ptr, format */
XawTextPosition pos = 0;
int front_len = 0;
int end_len = 0;
int end_pos = 0;
int i;
enum { FRONT, MIDDLE, END } place = FRONT;
enum form_type *ftp = (enum form_type *)client_data;
if (*ftp == FORM_AS_IS)
return;
if (called_back)
return;
else
called_back = True;
nullb.firstPos = 0;
nullb.length = 0;
nullb.ptr = NULL;
/*
* Scan the text for whitespace. Leading whitespace is deleted;
* embedded whitespace causes the rest of the text to be deleted.
*/
while (1) {
XawTextSourceRead(w, pos, &b, 1024);
if (b.length <= 0)
break;
nullb.format = b.format;
if (place == END) {
end_len += b.length;
continue;
}
for (i = 0; i < b.length; i++) {
char c;
c = *(b.ptr + i);
if (isspace(c) && (*ftp != FORM_NO_CC || c != ' ')) {
if (place == FRONT) {
front_len++;
continue;
} else {
end_pos = b.firstPos + i;
end_len = b.length - i;
place = END;
break;
}
} else
place = MIDDLE;
}
pos += b.length;
if (b.length < 1024)
break;
}
if (front_len)
XawTextSourceReplace(w, 0, front_len, &nullb);
if (end_len)
XawTextSourceReplace(w, end_pos - front_len,
end_pos - front_len + end_len, &nullb);
called_back = False;
}
/* Create a simple data entry popup */
Widget
create_form_popup(const char *name, XtCallbackProc callback,
XtCallbackProc callback2, enum form_type form_type)
{
char *widgetname;
Widget shell;
Widget dialog;
Widget w;
/* Create the popup shell */
widgetname = xs_buffer("%sPopup", name);
if (isupper(widgetname[0]))
widgetname[0] = tolower(widgetname[0]);
shell = XtVaCreatePopupShell(
widgetname, transientShellWidgetClass, toplevel,
NULL);
XtFree(widgetname);
XtAddCallback(shell, XtNpopupCallback, place_popup, (XtPointer)CenterP);
/* Create a dialog in the popup */
dialog = XtVaCreateManagedWidget(
ObjDialog, dialogWidgetClass, shell,
XtNvalue, "",
NULL);
XtVaSetValues(XtNameToWidget(dialog, XtNlabel),
NULL);
/* Add "Confirm" and "Cancel" buttons to the dialog */
w = XtVaCreateManagedWidget(
ObjConfirmButton, commandWidgetClass, dialog,
NULL);
XtAddCallback(w, XtNcallback, callback, (XtPointer)dialog);
if (callback2) {
w = XtVaCreateManagedWidget(
ObjConfirm2Button, commandWidgetClass, dialog,
NULL);
XtAddCallback(w, XtNcallback, callback2, (XtPointer)dialog);
}
w = XtVaCreateManagedWidget(
ObjCancelButton, commandWidgetClass, dialog,
NULL);
XtAddCallback(w, XtNcallback, cancel_button_callback, (XtPointer) shell);
if (form_type == FORM_AS_IS)
return shell;
/* Modify the translations for the objects in the dialog */
w = XtNameToWidget(dialog, XtNvalue);
if (w == NULL)
xs_warning("Cannot find \"%s\" in dialog", XtNvalue);
/* Set a callback for text modifications */
w = XawTextGetSource(w);
if (w == NULL)
XtWarning("Cannot find text source in dialog");
else
XtAddCallback(w, XtNcallback, popup_dialog_callback,
&forms[(int)form_type]);
return shell;
}
/*
* Read-only popups.
*/
struct rop {
const char *name; /* resource name */
XtGrabKind grab; /* grab kind */
Boolean is_error; /* is it? */
const char *itext; /* initial text */
Widget shell; /* pop-up shell */
Widget form; /* dialog form */
Widget cancel_button; /* cancel button */
abort_callback_t *cancel_callback; /* callback for cancel button */
Boolean visible; /* visibility flag */
};
static struct rop error_popup = {
"errorPopup", XtGrabExclusive, True,
"first line\nsecond line",
NULL, NULL, NULL, NULL,
False
};
static struct rop info_popup = {
"infoPopup", XtGrabNonexclusive, False,
"first line\nsecond line",
NULL, NULL, NULL, NULL,
False
};
static struct rop printer_error_popup = {
"printerErrorPopup", XtGrabExclusive, True,
"first line\nsecond line\nthird line\nfourth line",
NULL, NULL, NULL, NULL, False
};
static struct rop printer_info_popup = {
"printerInfoPopup", XtGrabNonexclusive, False,
"first line\nsecond line\nthird line\nfourth line",
NULL,
NULL, NULL, NULL, False
};
/* Called when OK is pressed in a read-only popup */
static void
rop_ok(Widget w unused, XtPointer client_data, XtPointer call_data unused)
{
struct rop *rop = (struct rop *)client_data;
XtPopdown(rop->shell);
}
/* Called when Cancel is pressed in a read-only popup */
static void
rop_cancel(Widget w unused, XtPointer client_data, XtPointer call_data unused)
{
struct rop *rop = (struct rop *)client_data;
XtPopdown(rop->shell);
if (rop->cancel_callback != NULL)
(*rop->cancel_callback)();
}
/* Called when a read-only popup is closed */
static void
rop_popdown(Widget w unused, XtPointer client_data, XtPointer call_data unused)
{
struct rop *rop = (struct rop *)client_data;
rop->visible = False;
if (exiting && rop->is_error)
x3270_exit(1);
}
/* Initialize a read-only pop-up. */
static void
rop_init(struct rop *rop)
{
Widget w;
if (rop->shell != NULL)
return;
rop->shell = XtVaCreatePopupShell(
rop->name, transientShellWidgetClass, toplevel,
NULL);
XtAddCallback(rop->shell, XtNpopupCallback, place_popup,
(XtPointer) CenterP);
XtAddCallback(rop->shell, XtNpopdownCallback, rop_popdown, rop);
/* Create a dialog in the popup */
rop->form = XtVaCreateManagedWidget(
ObjDialog, dialogWidgetClass, rop->shell,
NULL);
XtVaSetValues(XtNameToWidget(rop->form, XtNlabel),
XtNlabel, rop->itext,
NULL);
/* Add "OK" button to the dialog */
w = XtVaCreateManagedWidget(
ObjConfirmButton, commandWidgetClass, rop->form,
NULL);
XtAddCallback(w, XtNcallback, rop_ok, rop);
/* Add an unmapped "Cancel" button to the dialog */
rop->cancel_button = XtVaCreateManagedWidget(
ObjCancelButton, commandWidgetClass, rop->form,
XtNright, w,
XtNmappedWhenManaged, False,
NULL);
XtAddCallback(rop->cancel_button, XtNcallback, rop_cancel, rop);
/* Force it into existence so it sizes itself with 4-line text */
XtRealizeWidget(rop->shell);
}
/* Pop up a dialog. Common logic for all forms. */
static void
popup_rop(struct rop *rop, abort_callback_t *a, const char *fmt, va_list args)
{
(void) vsprintf(vmsgbuf, fmt, args);
if (!rop->shell) {
(void) fprintf(stderr, "%s: %s\n", programname, vmsgbuf);
exit(1);
}
if (rop->is_error && sms_redirect()) {
sms_error(vmsgbuf);
return;
}
XtVaSetValues(rop->form, XtNlabel, vmsgbuf, NULL);
if (a != NULL)
XtMapWidget(rop->cancel_button);
else
XtUnmapWidget(rop->cancel_button);
rop->cancel_callback = a;
if (!rop->visible) {
if (rop->is_error)
ring_bell();
rop->visible = True;
popup_popup(rop->shell, rop->grab);
}
}
static void
error_exit(void)
{
x3270_exit(0);
}
/* Pop up an error dialog. */
void
popup_an_error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
popup_rop(&error_popup, appres.reconnect? error_exit: NULL, fmt, args);
va_end(args);
}
/* Pop down an error dialog. */
void
popdown_an_error(void)
{
if (error_popup.visible) {
XtPopdown(error_popup.shell);
}
}
/* Pop up an error dialog, based on an error number. */
void
popup_an_errno(int errn, const char *fmt, ...)
{
va_list args;
char *s;
va_start(args, fmt);
(void) vsprintf(vmsgbuf, fmt, args);
va_end(args);
s = XtNewString(vmsgbuf);
if (errn > 0)
popup_an_error("%s:\n%s", s, strerror(errn));
else
popup_an_error(s);
XtFree(s);
}
/* Pop up an info dialog. */
void
popup_an_info(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
popup_rop(&info_popup, NULL, fmt, args);
va_end(args);
}
/*
* Produce a result of some sort. If there is a script running, return it
* as the value; otherwise, pop it up as an info.
*/
void
action_output(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (sms_redirect()) {
char buf[4096];
(void) vsprintf(buf, fmt, args);
sms_info("%s", buf);
} else
popup_rop(&info_popup, NULL, fmt, args);
va_end(args);
}
/* Initialization. */
void
error_popup_init(void)
{
rop_init(&error_popup);
}
void
info_popup_init(void)
{
rop_init(&info_popup);
}
void
printer_popup_init(void)
{
if (printer_error_popup.shell != NULL)
return;
rop_init(&printer_error_popup);
rop_init(&printer_info_popup);
}
/* Query. */
Boolean
error_popup_visible(void)
{
return error_popup.visible;
}
/*
* Printer pop-up.
* Allows both error and info popups, and a cancel button.
* is_err If True, this is an error pop-up. If false, this is an info
* pop-up.
* a If non-NULL, the Cancel button is enabled, and this is the
* callback function for it. If NULL, there will be no Cancel
* button.
* fmt... printf()-like format and arguments.
*/
void
popup_printer_output(Boolean is_err, abort_callback_t *a, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
popup_rop(is_err? &printer_error_popup: &printer_info_popup, a, fmt,
args);
va_end(args);
}
/*
* Script actions
*/
void
Info_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Info_action, event, params, num_params);
if (check_usage(Info_action, *num_params, 1, 1) < 0)
return;
popup_an_info(params[0]);
}